const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`;
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
const attribute =
  /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/; //匹配属性
const startTagOpen = new RegExp(`^<${qnameCapture}`); // 匹配开始标签
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`); //匹配结束标签全部内容</div>
const startTagClose = /^\s*(\/?)>/; //匹配标签结束的>
export const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g;

export function parseHTML(html) {
  let root = null;
  let currentParent;
  let stack = [];
  const ELEMENT_TYPE = 1;
  const TEXT_TYPE = 3;

  function createASTElement(tagName, attrs) {
    return {
      tag: tagName,
      type: ELEMENT_TYPE,
      children: [],
      attrs,
      parent: null,
    };
  }

  // 解析开始标签
  function start(tagName, attrs) {
    //   console.log("开始标签：", tagName, "属性是：", attrs);
    let element = createASTElement(tagName, attrs);
    if (!root) {
      root = element;
    }
    currentParent = element; // 把当前元素标记成父ast树
    stack.push(element); //将开始标签加入栈
  }

  // 解析结束标签
  function end(tagName) {
    // console.log("结束标签：", tagName);
    let element = stack.pop(); // 取栈中的最后一个元素,拿到的是ast对象
    currentParent = stack[stack.length - 1]; // 判断当前元素的父节点，
    if (currentParent) {
      // 父节点存在，设置对应关系
      element.parent = currentParent;
      currentParent.children.push(element);
    }
  }

  // 解析文本
  function chars(text) {
    //   console.log("文本是", text);
    text = text.replace(/\s/g, ""); // 把空格都清空
    if (text) {
      currentParent.children.push({
        text,
        type: TEXT_TYPE,
      });
    }
  }
  while (html) {
    let textEnd = html.indexOf("<");
    if (textEnd == 0) {
      // 如果当前索引为0 肯定是一个标签【开始标签或者结束标签】
      let startTagMatch = parseStartTag(); // 通过方法获取匹配的结果 tagName attrs
      if (startTagMatch) {
        let { tagName, attrs } = startTagMatch;
        start(tagName, attrs);
        continue; //如果开始标签匹配完毕后，继续下一次 匹配
      }

      // 匹配结束标签
      let endTagMatch = html.match(endTag);
      if (endTagMatch) {
        advance(endTagMatch[0].length);
        end(endTagMatch[1]);
        continue;
      }
    }
    let text;
    if (textEnd >= 0) {
      // 说明开始不是 < 符号,但是后边还有该符号
      text = html.substring(0, textEnd);
    }
    if (text) {
      advance(text.length);
      chars(text);
      //   break;
    }
    // console.log("匹配一次后剩下html结构，", html);
  }

  function advance(n) {
    html = html.substring(n);
  }

  function parseStartTag() {
    let start = html.match(startTagOpen);
    if (start) {
      const match = {
        tagName: start[1],
        attrs: [],
      };
      advance(start[0].length); // 将匹配到的开始标签删除
      let end, attr;
      // html.match(startTagClose)用来匹配 > ,判断是否是标签的结束符号
      while (
        !(end = html.match(startTagClose)) &&
        (attr = html.match(attribute)) // 是属性元素
      ) {
        // 将属性进行解析
        advance(attr[0].length);
        match.attrs.push({
          name: attr[1],
          value: attr[3] || attr[4] || attr[5],
        });
      }
      if (end) {
        // 如果存在开始标签的结束符号>
        advance(end[0].length);
        return match;
      }
    }
  }
  return root;
}
